#include "mcmcSW.h"
#include "mcRand.h"

LinkList<int> list_comp,list_rest,list_nb;

/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// construction & destruction
MCMC_SW_Sample_2Way::MCMC_SW_Sample_2Way()
{
	p_cues_with_all_gregions = NULL;
}

MCMC_SW_Sample_2Way::~MCMC_SW_Sample_2Way()
{
	Free();
}

void MCMC_SW_Sample_2Way::Free(void)
{
	if (p_cues_with_all_gregions != NULL)
		delete []p_cues_with_all_gregions;
	p_cues_with_all_gregions = NULL;
}

// operators


// operations

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void MCMC_SW_Sample_2Way::Set(MCMC_Layer_Regions &layer_region, MCMC_ModelSupervisor &model_supervisor)
{
	player_region = &layer_region;
	pmodel_supervisor = &model_supervisor;

	// currently there are only three cues
	//rf_cue_other.Set(0, NUM_MODEL_TYPE, 1);
	rf_cue_other.Set(0, 2,  1);

	// space
	mx_sampled_edge.SetDimension(layer_region.MaxGRegionIndex(), layer_region.MaxGRegionIndex());
	mx_sampled_edge.InitValue(0);

	// what are the neighboring gregions for the selected component
	vc_sign_neighbors.SetRowVector(layer_region.MaxGRegionIndex());
	vc_sign_neighbors.InitValue(0);

	if (p_cues_with_all_gregions != NULL)
		delete []p_cues_with_all_gregions;
	p_cues_with_all_gregions = new MCMC_CombinedAffinity[layer_region.MaxGRegionIndex()];

	vc_involved_order_indexid.SetRowVector(layer_region.MaxGRegionIndex());
	vc_involved_order_indexid.InitValue(-1);

	vc_nb_order_of_indexid.SetRowVector(layer_region.MaxGRegionIndex());
	vc_nb_order_of_indexid.InitValue(-1);

	vc_flag_selected.SetRowVector(player_region->MaxGRegionIndex());
	vc_flag_selected.InitValue(0);
}

void MCMC_SW_Sample_2Way::ClearRecord(void)
{
	int	i,j;
	MCMC_RegionElement	*pregion;

	// involved regions
	for (i=0; i<vc_involved_indexid.size(); i++)
	{
		pregion = player_region->GetRegionFromIndexId(vc_involved_indexid(i));
		assert(pregion != NULL);

		// the edge
		assert(pregion->paffinity_map != NULL);

		pregion->paffinity_map->RemoveEdges();
		for (j=i+1; j<vc_involved_indexid.size(); j++)
		{
			mx_sampled_edge(vc_involved_indexid(i), vc_involved_indexid(j)) = 0;
			mx_sampled_edge(vc_involved_indexid(j), vc_involved_indexid(i)) = 0;
		}

		vc_involved_order_indexid(vc_involved_indexid(i)) = -1;
	}

	int indexid;

	// neighbors
	for (i=0; i<vc_nb_indexid.size(); i++)
	{
		indexid = vc_nb_indexid(i);
		p_cues_with_all_gregions[indexid].Clear();
		vc_nb_order_of_indexid(indexid) = -1;
	}

	// selected region
	bool bgo;

	bgo = list_selected.GetFirst(indexid);
	while (bgo)
	{
		vc_flag_selected(indexid) = 0;
		bgo = list_selected.GetNext(indexid);
	}
	list_selected.Empty();
}

double MCMC_SW_Sample_2Way::Propose(const int indexid, LinkList<int> &list_proposed, int &cue_selected_comp_rt, int &indexid_nb_rt,
							 LinkList<int> &list_leftover)
{
	int			index_temp;
	MCMC_GRegion	*pgregion;

	pgregion = (MCMC_GRegion*)player_region->GetRegionFromIndexId(indexid);
	if (pgregion == NULL)
		return 0.0f;

	int i=0;

	// get all the elements in this g-region
	vc_involved_indexid.SetRowVector(pgregion->NumRegions());
	index_temp = pgregion->GetFirstRegion();
	while (index_temp >= 0)
	{
		// mark this region
		vc_involved_order_indexid(index_temp) = i;
		vc_involved_indexid(i) = index_temp;
		i++;

		index_temp = pgregion->GetNextRegion();
	}

	// propose the cues
	double	Q1_2;

	// prepare bonds
	PrepareBonds();
	// sample the edges according the bonds
	SampleEdges();
	// to randomly propose a connected component

	Q1_2 = ProposeComponent();
	Q1_2 *=	ProposeNeighbor(indexid_nb);
	indexid_nb_rt = indexid_nb;
	cue_selected_comp_rt = cue_4ccp;

	list_proposed = list_selected;
	list_leftover.Empty();
	// the leftover
	for (i=0; i<vc_involved_indexid.size(); i++)
	{
		if (vc_flag_selected(vc_involved_indexid(i)) <= 0)
			list_leftover.Insert(vc_involved_indexid(i));
	}

	return Q1_2;
}


// prepare to compute the probability for coming back
void MCMC_SW_Sample_2Way::ToComputeComingBack(const int indexid_new1, const int indexid_new2)
{
	int	i,j;
	MCMC_RegionElement	*pregion;
	MCMC_GRegion		*pgregion_new1;

	// involved regions
	for (i=0; i<vc_involved_indexid.size(); i++)
	{
		pregion = player_region->GetRegionFromIndexId(vc_involved_indexid(i));
		assert(pregion != NULL);

		// the edge
		assert(pregion->paffinity_map != NULL);
		pregion->paffinity_map->RemoveEdges();
		for (j=i+1; j<vc_involved_indexid.size(); j++)
		{
			mx_sampled_edge(vc_involved_indexid(i), vc_involved_indexid(j)) = 0;
			mx_sampled_edge(vc_involved_indexid(j), vc_involved_indexid(i)) = 0;
		}

		vc_involved_order_indexid(vc_involved_indexid(i)) = -1;
	}
	
	if (indexid_new1 >= 0)
		p_cues_with_all_gregions[indexid_new1].Clear();

	// at this time pgregion_nb has already included regions in the CCP
	pgregion_new1 =  (MCMC_GRegion*)player_region->GetRegionFromIndexId(indexid_new1);
	if (pgregion_new1 != NULL)
		vc_involved_indexid.SetRowVector(pgregion_new1->NumRegions());
	else
		vc_involved_indexid.SetRowVector(list_selected.Num());

	bool	bgo;
	int		indexid1;

	// set involved regions
	i = 0;
	// from the selected neighbors
	if (pgregion_new1 != NULL)
	{
		indexid1 = pgregion_new1->GetFirstRegion();
		while (indexid1 >= 0)
		{
			vc_involved_indexid(i) = indexid1;
			vc_involved_order_indexid(indexid1) = i++;

			indexid1 = pgregion_new1->GetNextRegion();
		}
	}
	else
	{
		bgo = list_selected.GetFirst(indexid1);
		while (bgo)
		{
			vc_involved_indexid(i) = indexid1;
			vc_involved_order_indexid(indexid1) = i++;

			bgo = list_selected.GetNext(indexid1);
		}
	}
}

double MCMC_SW_Sample_2Way::Q_ProposeBack(const int indexid_new1, const int indexid_new2)
{
	double q_component,q_cut,q_nb_cue,Q2_1;

	// prepare
	ToComputeComingBack(indexid_new1, indexid_new2);

	// prepare bonds
	PrepareBonds();

	RF	rf_regions;
	// compute the probability of selecting the component
	PrepareToProposeComponent(rf_regions);
	q_component = QComponent(rf_regions);
	// cut
	q_cut = QCut();
	
	int id_buf=indexid_nb;
	indexid_nb = indexid_new2;
	// neighbors
	q_nb_cue = QProposeNeighbor();

	indexid_nb = id_buf;

	// the overall proposal probability
	Q2_1 = q_component*q_cut*q_nb_cue;

	return Q2_1;
}

/////////////
///---- Cues
void MCMC_SW_Sample_2Way::PrepareToCombineTwoCueTypes(int indexid_gregion)
{
	// let them to be uniform at this moment
	/*bool *p_sign=NULL;
	p_sign = pmodel_supervisor->GetSelectedModelSign();
	rf_cue_other.InitValue(0.0);
	
		if (  p_sign[TOC_Intensity] ) rf_cue_other.SetOneBin(TOC_Intensity, 1.0);
		if (  p_sign[TOC_Smooth] )    rf_cue_other.SetOneBin(TOC_Smooth, 1.0);
		if (  p_sign[TOC_Texture] ) rf_cue_other.SetOneBin(TOC_Texture, 1.0);
		if (  p_sign[TOC_Face] ) rf_cue_other.SetOneBin(TOC_Face, 1.0);
		if (  p_sign[TOC_Text] ) rf_cue_other.SetOneBin(TOC_Text, 1.0);
		if (  p_sign[TOC_2DColor] ) rf_cue_other.SetOneBin(TOC_2DColor, 1.0);
		if (  p_sign[TOC_3DColor] ) rf_cue_other.SetOneBin(TOC_3DColor, 1.0);
		if (  p_sign[TOC_3DColor_Mix] ) rf_cue_other.SetOneBin(TOC_3DColor_Mix, 1.0);
		if (  p_sign[TOC_LUVColor] ) rf_cue_other.SetOneBin(TOC_LUVColor, 1.0);
		if (  p_sign[TOC_LUVColorMix] ) rf_cue_other.SetOneBin(TOC_LUVColorMix, 1.0);
		if (  p_sign[TOC_LUVSurface] ) rf_cue_other.SetOneBin(TOC_LUVSurface, 1.0);		
	*/
	int cue_current_temp;
	if ( pmodel_supervisor->IsColorImage() )
		cue_current_temp = cue_current - 8;
	else
		cue_current_temp = cue_current;
	rf_cue_other.InitValue(1.0);
	rf_cue_other.SetOneBin(cue_current_temp, 0.5);
	rf_cue_other.normalize();
}

double MCMC_SW_Sample_2Way::QProposeTwoCueTypes(int indexid_gregion)
{
	PrepareToCombineTwoCueTypes(indexid_gregion);

	int cue_other_tocombine_temp;
	if ( pmodel_supervisor->IsColorImage() )
		cue_other_tocombine_temp = cue_other_tocombine - 8;
	else
		cue_other_tocombine_temp = cue_other_tocombine;

	return rf_cue_other.pdf(cue_other_tocombine_temp);
}


double MCMC_SW_Sample_2Way::ProposeTwoCueTypes(int indexid_gregion)
{
	// prepare
	PrepareToCombineTwoCueTypes(indexid_gregion);

	// propose
	cue_other_tocombine = rf_cue_other.SamplingIntNonSetCdf();

	if ( pmodel_supervisor->IsColorImage() ) cue_other_tocombine += 8;

	return QProposeTwoCueTypes(indexid_gregion);
}

void MCMC_SW_Sample_2Way::ExchangeCueValues(void)
{
	if (cue_4ccp == cue_current)
		SwapInt(cue_4ccp, cue_current);
	else
	{
		cue_other_tocombine = cue_current;
		SwapInt(cue_4ccp, cue_current);
	}
}


/////////////
///---- Bonds

bool MCMC_SW_Sample_2Way::PrepareBonds(void)
{
	MCMC_RegionElement *pregion;
	mcmcVector<int>			vc_cue_type;

	if (cue_current == cue_other_tocombine)
	{
		vc_cue_type.SetRowVector(1);
		
		vc_cue_type(0) = cue_current;
		if ( pmodel_supervisor->IsColorImage() ) vc_cue_type(0) -= 8;
	}
	else
	{
		vc_cue_type.SetRowVector(2);
	
		vc_cue_type(0) = cue_current;
		vc_cue_type(1) = cue_other_tocombine;

		if ( pmodel_supervisor->IsColorImage() )
		{
			vc_cue_type(0) -= 8;
			vc_cue_type(1) -= 8;
		}
	}

	// prepare affinity map
	for (int i=0; i<vc_involved_indexid.size(); i++)
	{
		pregion = player_region->GetRegionFromIndexId(vc_involved_indexid(i));
		assert(pregion != NULL && pregion->paffinity_map!=NULL);

		pregion->paffinity_map->PrepareBondsMasked(vc_cue_type, &vc_involved_order_indexid);
	}
	return true;
}

void MCMC_SW_Sample_2Way::SampleEdges(void)
{
	MCMC_RegionElement *pregion;
	RF	rf_on_off;

	rf_on_off.Set(0, 1, 1);
	// prepare affinity map
	for (int i=0; i<vc_involved_indexid.size(); i++)
	{
		pregion = player_region->GetRegionFromIndexId(vc_involved_indexid(i));
		assert(pregion!=NULL && pregion->paffinity_map!=NULL);

		pregion->paffinity_map->SampleEdges(mx_sampled_edge, rf_on_off, vc_involved_indexid(i), &vc_involved_order_indexid);
	}
}

///////////////////
///---- Components

double MCMC_SW_Sample_2Way::ProposeComponent(void)
{
	double	Q;
	RF		rf_regions;
	int		i,indexid1;

	if (!PrepareToProposeComponent(rf_regions))
		return 0.0f;

	// propose an indexid
	i = IntClose(rf_regions.SamplingNonSetCdf());
	indexid1 = vc_involved_indexid(i);

	// find the connected component

	FindConnectedComponent(indexid1);

	// proposal probability of choosing the component
	Q = QComponent(rf_regions);
	// the cut
	Q *= QCut();

	return Q;
}

bool MCMC_SW_Sample_2Way::PrepareToProposeComponent(RF& rf_regions)
{
	if (vc_involved_indexid.size() > 0)
	{
		rf_regions.Set(0, vc_involved_indexid.size()-1, 1);
		for (int i=0; i<vc_involved_indexid.size(); i++)
			rf_regions.SetOneBin(i, 1.0);
		rf_regions.normalize();

		return true;
	}
	else
		return false;
}

double MCMC_SW_Sample_2Way::QComponent(RF &rf_regions)
{
	int		indexid1;
	bool	bgo;
	double	Q;

	// compute the probability to select the connected component
	Q = 0.0;
	bgo = list_selected.GetFirst(indexid1);
	while (bgo)
	{
		Q += (double)rf_regions.pdf(vc_involved_order_indexid(indexid1));
		bgo = list_selected.GetNext(indexid1);
	}
	return Q;
}

double MCMC_SW_Sample_2Way::QCut(void)
{
	bool	bgo;
	int		indexid1,indexid2;
	double	q_cut;
	MCMC_RegionElement	*pregion;
	MCMC_CombinedAffinity	*pcue;

	bgo = list_selected.GetFirst(indexid1);
	// compute the total probability of cutting
	q_cut = 1.0;
	while (bgo)
	{
		pregion = player_region->GetRegionFromIndexId(indexid1);
		assert(pregion != NULL && pregion->paffinity_map!=NULL);

		pcue = pregion->paffinity_map->GetFirstCombinedCue(&indexid2);
		while (pcue != NULL)
		{
			if (vc_involved_order_indexid(indexid2)>=0 && // in the gregion
				vc_flag_selected(indexid2)==0)			// not in the selected component
				q_cut *= (1.0-pcue->Q());

			pcue = pregion->paffinity_map->GetNextCombinedCue(&indexid2);
		}
		bgo = list_selected.GetNext(indexid1);
	}
 	return q_cut;
}



void MCMC_SW_Sample_2Way::FindConnectedComponent(const int indexid1)
{
	LinkList<int>		list_queue;
	int					id_temp1,id_temp2;
	MCMC_RegionElement	*pregion;
	MCMC_CombinedAffinity	*pcue;

	// initlization
	list_selected.Empty();

	list_queue.Insert(indexid1);

	// get all the connected vertices
	while (list_queue.Num() > 0)
	{
		assert(list_queue.PopOut(id_temp1));
		list_selected.Insert(id_temp1);
		vc_flag_selected(id_temp1) = 1;

		// get this region element
		pregion = player_region->GetRegionFromIndexId(id_temp1);
		assert(pregion!=NULL && pregion->paffinity_map!=NULL);

		pcue = pregion->paffinity_map->GetFirstCombinedCue(&id_temp2);
		while (pcue != NULL)
		{
			if (vc_flag_selected(id_temp2)==0 && mx_sampled_edge(id_temp1, id_temp2)==1)
			{
				list_queue.Insert(id_temp2);
				vc_flag_selected(id_temp2) = 1;
			}
			pcue = pregion->paffinity_map->GetNextCombinedCue(&id_temp2);
		}
	}
}

///////////////////
///---- Neighbors


void MCMC_SW_Sample_2Way::CompositeCuesWithNeighbors(LinkList<int> &list_gregion_nb, bool bpropose)
{
	bool	bgo;
	int		i,indexid_region_temp,indexid_nb1,indexid_temp2;
	MCMC_RegionElement	*pregion_element,*paregion_nb,*pregion_org;
	MCMC_CombinedAffinity	*pcue;
	int		idparent_org;
	McPoint2D	pt_center1,pt_center2;
	
	assert(list_selected.GetFirst(indexid_region_temp));
	pregion_element = player_region->GetRegionFromIndexId(indexid_region_temp);
	assert(pregion_element != NULL);
	idparent_org = pregion_element->IndexIdParent();
	pregion_org = player_region->GetRegionFromIndexId(idparent_org);
	assert(pregion_org != NULL);
	pt_center1 = pregion_org->Center();
	
	if (!bpropose)
	{
		// clear the record for the previous neighbor
		for (i=0; i<vc_nb_indexid.size(); i++)
			vc_nb_order_of_indexid(vc_nb_indexid(i)) = -1;
	}

	// all possible neighbors
	LinkList<int> list_topnode_regions;
	MCMC_RegionElement	*pregion_temp;
	float q,dist_max;
	
	dist_max = (float)sqrt(pow((float)player_region->height, float(2.0))+pow((float)player_region->width, float(2.0)));

	player_region->GetAllTopNodeRegions(list_topnode_regions);
	bgo = list_topnode_regions.GetFirst(indexid_region_temp);
	while (bgo)
	{
		vc_nb_order_of_indexid(indexid_region_temp) = 0;

		pregion_temp = player_region->GetRegionFromIndexId(indexid_region_temp);
		if (pregion_temp != NULL)
			pt_center2 = pregion_temp->Center();
		
		q = (float)((1.0-pt_center1.Distance(pt_center2)/dist_max)*0.15);

		p_cues_with_all_gregions[indexid_region_temp].Init(q);

		bgo = list_topnode_regions.GetNext(indexid_region_temp);
	}
	vc_nb_order_of_indexid(idparent_org) = -1;
	p_cues_with_all_gregions[idparent_org].Init(0.0);
	
	num_cues = 0;
	// g-regions in the component
	bgo = list_selected.GetFirst(indexid_region_temp);
	while (bgo)
	{
		pregion_element = player_region->GetRegionFromIndexId(indexid_region_temp);
		assert(pregion_element != NULL && pregion_element->paffinity_map != NULL);

		// retrieve all its neighboring regions
		pcue = pregion_element->paffinity_map->GetFirstCombinedCue(&indexid_nb1);

		while (pcue != NULL)
		{
			paregion_nb = player_region->GetRegionFromIndexId(indexid_nb1);
			assert(paregion_nb != NULL);

			num_cues = max(num_cues, pcue->Num());

			// get the gregion id
			indexid_temp2 = paregion_nb->ToppestLevelIndexId();

			if (vc_flag_selected(indexid_temp2)==0 && indexid_temp2!=idparent_org)
			{
				vc_nb_order_of_indexid(indexid_temp2) = 0;

				// cumulate the cues
				p_cues_with_all_gregions[indexid_temp2].AddFrom(*pcue);
			}

			pcue = pregion_element->paffinity_map->GetNextCombinedCue(&indexid_nb1);
		}
		bgo = list_selected.GetNext(indexid_region_temp);
	}

	
	int j=0;

	// put found regions into the list
	list_gregion_nb.Empty();
	for (i=0; i<vc_nb_order_of_indexid.size(); i++)
	{
		if (vc_nb_order_of_indexid(i) >= 0)
		{
			list_gregion_nb.Insert(i);
			vc_nb_order_of_indexid(i) = j++;
		}
	}
}

// prepare the proposal probabilities
bool MCMC_SW_Sample_2Way::PrepareToProposeNeighborAndCueType(bool bpropose)
{
	LinkList<int>	list_gregion_nb;

	// prepare the composite cues with all the neighbors
	CompositeCuesWithNeighbors(list_gregion_nb, bpropose);

	list_gregion_nb.ToVector(vc_nb_indexid);

	int i,j;
	MCMC_CombinedAffinity	*pcom_cue;
	MCMC_Affinity			*pcue;

	// set the random field
	//  it actually requires 2d only
	rf_neighbor_and_cuetype.Set(1, 1, 1,   0,num_cues-1,1,   -1,vc_nb_indexid.size()-1,1);
	int cue_current_temp=-1, cue_other_tocombine_temp=-1; //add by wtf
	for (i=0; i<vc_nb_indexid.size(); i++)
	{
		pcom_cue = &p_cues_with_all_gregions[vc_nb_indexid(i)];

		for (j=0; j<pcom_cue->Num(); j++)
		{
			if ( pmodel_supervisor->IsColorImage() )
			{
				cue_current_temp = cue_current - 8;
				cue_other_tocombine_temp = cue_other_tocombine - 8;
			}
			if (j==cue_current_temp || j==cue_other_tocombine_temp) //(j==cue_current || j==cue_other_tocombine)
			{
				pcue = pcom_cue->GetCue(j);
				if (pcue != NULL)
					rf_neighbor_and_cuetype.SetOneBin(1, j, i, pcue->q);
			}
		}
	}

	// normalize
	rf_neighbor_and_cuetype.normalize();
	for (j=0; j<num_cues; j++)
		rf_neighbor_and_cuetype.SetOneBin(1, j, -1, 0.1/num_cues);
	return rf_neighbor_and_cuetype.normalize();
}

// propose
double MCMC_SW_Sample_2Way::ProposeNeighbor(int &indexid_nb1)
{
	double dtemp1,dtemp2,dtemp3;

	// prepare to propose neighbor
	if (PrepareToProposeNeighborAndCueType())
	{
		// sample
		rf_neighbor_and_cuetype.SamplingNonSetCdf(dtemp1, dtemp2, dtemp3);

		cue_4ccp = IntClose(dtemp2);
		if ( pmodel_supervisor->IsColorImage() ) cue_4ccp += 8;
		indexid_nb1 = IntClose(dtemp3);
		if (indexid_nb1 >= 0)
			indexid_nb1 = vc_nb_indexid(indexid_nb1);

		return rf_neighbor_and_cuetype.pdf(dtemp1, dtemp2, dtemp3);
	}
	else
	{
		indexid_nb1 = -1;
		return 0.0;
	}
}


double  MCMC_SW_Sample_2Way::QProposeNeighbor(void)
{
	// prepare to propose neighbor
	PrepareToProposeNeighborAndCueType(false);

	int i;

	if (indexid_nb>=0 && indexid_nb<vc_nb_order_of_indexid.size())
	{
		i = vc_nb_order_of_indexid(indexid_nb);
		if (i < 0)
			i = -2;
	}
	else
		i = -1;

	// sample
	int cue_4ccp_temp;
	if ( pmodel_supervisor->IsColorImage() )
		cue_4ccp_temp = cue_4ccp - 8;
	else
		cue_4ccp_temp = cue_4ccp;

	return rf_neighbor_and_cuetype.pdf(1, cue_4ccp_temp, i);
}



/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////

// construction & destruction
MCMC_SW_Cuts_2Way::MCMC_SW_Cuts_2Way()
{
	player_region = NULL;
	pmodel_supervisor = NULL;

	for (int i=0; i<4; i++)
		Info[i][0] = '\0';
}

MCMC_SW_Cuts_2Way::~MCMC_SW_Cuts_2Way()
{
	player_region = NULL;
	pmodel_supervisor = NULL;
}

void MCMC_SW_Cuts_2Way::Set(MCMC_Layer_Regions &graph, MCMC_ModelSupervisor &model_supervisor)
{
	player_region = &graph;
	pmodel_supervisor = &model_supervisor;

	sw_cut.Set(graph, model_supervisor);

	rf_gregions.Set(0, graph.MaxGRegionIndex()-1, 1);
}

bool MCMC_SW_Cuts_2Way::UngroupAndGroup(int &indexid_new1, int &indexid_new2,
										  LinkList<int> &list_proposed, LinkList<int> &list_left, int indexid_nb)
{
	if (list_proposed.Num() <= 0)
		return false;
	
	int id_temp;
	MCMC_GRegion *pgregion1,*pgregion_nb;
	
	// the proposed gregion
	list_proposed.GetFirst(id_temp);
	pgregion1 = (MCMC_GRegion*)player_region->GetRegionFromIndexId(
					player_region->GetRegionFromIndexId(id_temp)->IndexIdParent());
	assert(pgregion1 != NULL);
	pgregion_nb = (MCMC_GRegion*)player_region->GetRegionFromIndexId(indexid_nb);

	// the proposed neighbor
	
	bool bgo;


	// different cases
	if (pgregion1->NumRegions() == list_proposed.Num())
	{
		indexid_new2 = -1;

		// all the child regions are proposed, no need to perform ungrouping
		if (pgregion_nb == NULL)
			// no change is made
			indexid_new1 = pgregion1->IndexId();
		else
		{
			// delete the old gregion and merge all the regions
			// with the neighbor
			player_region->DeleteGRegion(pgregion1->Id());
			
			bgo = list_proposed.GetFirst(id_temp);
			while (bgo)
			{
				assert(id_temp >= 0);
				pgregion_nb->AddRegion(id_temp);

				bgo = list_proposed.GetNext(id_temp);
			}
			indexid_new1 = pgregion_nb->IndexId();
		}
	}
	else
	{
		// ungroup the region proposed first
		bgo = list_proposed.GetFirst(id_temp);
		while (bgo)
		{
			assert(id_temp >= 0);
			pgregion1->DeleteRegion(id_temp);

			bgo = list_proposed.GetNext(id_temp);
		}
		indexid_new2 = pgregion1->IndexId();
	
		if (pgregion_nb == NULL)
		{
			// need to propose a new gregion
			MCMC_GRegion *pgregion_new;
			pgregion_new = player_region->GetGRegion(player_region->NewGRegion());
			assert(pgregion_new != NULL);
			
			// record
			indexid_new1 = pgregion_new->IndexId();

			bgo = list_proposed.GetFirst(id_temp);
			while (bgo)
			{
				assert(id_temp >= 0);
				pgregion_new->AddRegion(id_temp);

				bgo = list_proposed.GetNext(id_temp);
			}
		}
		else
		{
			bgo = list_proposed.GetFirst(id_temp);
			while (bgo)
			{
				assert(id_temp >= 0);
				pgregion_nb->AddRegion(id_temp);

				bgo = list_proposed.GetNext(id_temp);
			}

			// record
			indexid_new1 = pgregion_nb->IndexId();
		}
	}

	return true;
}

bool MCMC_SW_Cuts_2Way::TryAccept(void)
{
	Rand	rf_accept;
	double	rate_acceptance;

	baccept = false;
	if (Q2_1>0.0 && Q1_2>0.0)
	{
		rate_acceptance = Q2_1/Q1_2*exp(-(energy2-energy1)/player_region->GetT());
		baccept = rf_accept.Accept(min(1.0,rate_acceptance));

		if (baccept)
			sprintf(Info[1], "Accepted");
		else
			sprintf(Info[1], "Not accepted");
	}
	else
		assert(false);
	
	Info[2][0] = '\0';
	Info[3][0] = '\0';
	
	return baccept;
}

void MCMC_SW_Cuts_2Way::DoAction(void)
{
	MCMC_GRegion *pgregion;
	
	if (baccept)
	{
		// accept this proposal
		// find the starting contour segment for the regions
		pgregion = (MCMC_GRegion*)player_region->GetRegionFromIndexId(indexid_new1);
		assert(pgregion != NULL);
		pgregion->FindTheStartCSeg();

		pgregion = (MCMC_GRegion*)player_region->GetRegionFromIndexId(indexid_new2);
		if (pgregion != NULL)
			pgregion->FindTheStartCSeg();
	}
	else
	{
		// restore the old gregions
		if (indexid_new1 >= 0)
		{
			// delete the two new g-regions
			pgregion = (MCMC_GRegion*)player_region->GetRegionFromIndexId(indexid_new1);
			assert(pgregion != NULL);
			player_region->DeleteGRegion(pgregion->Id());

			pgregion = (MCMC_GRegion*)player_region->GetRegionFromIndexId(indexid_new2);
			if (pgregion != NULL)
				player_region->DeleteGRegion(pgregion->Id());
			
			// recover the old g-regions
			assert(indexid_tochange >=0);
			pgregion = player_region->GetGRegion(player_region->NewGRegion());
			assert(pgregion != NULL);
			*pgregion = gregion_buf1;
			pgregion->SetParentIdForChildRegions();
			
			if (indexid_nb >=0)
			{
				pgregion = player_region->GetGRegion(player_region->NewGRegion());
				assert(pgregion != NULL);
				*pgregion = gregion_buf2;
			
				pgregion->SetParentIdForChildRegions();
			}
		}
	}
}

double MCMC_SW_Cuts_2Way::QForRegion(const double crying_voice, const int num_aregions)
{
/*	
	if (num_aregions == 1)
		return max(10.0, crying_voice);
	else
		return max(10.0, sqrt(crying_voice)*pow(num_aregions, 0.5));
*/
	return pow(float(max(1.0, crying_voice)),0.3f)*pow((float)num_aregions, 0.5f);

//	return sqrt((double)num_aregions);
}


//-- propose a gergion
bool MCMC_SW_Cuts_2Way::PrepareToProposeGRegion(RF &rf_gregions)
{
	if (player_region->NumGRegions() <= 0)
		return false;
	
	MCMC_GRegion *pgregion;
	double	cue_to_propose;

	// prepare which gregion
	rf_gregions.InitValue(0.0);

	pgregion = player_region->GetGRegion(player_region->GetFirstGRegion());
	while (pgregion != NULL)
	{
		if (pgregion != NULL && pgregion->IndexIdParent() < 0)
		{
			cue_to_propose = QForRegion(pgregion->Model()->crying_voice, pgregion->NumAtomicRegions());

			rf_gregions.SetOneBin(pgregion->IndexId(), cue_to_propose);
		}

		pgregion = player_region->GetGRegion(player_region->GetNextGRegion());
	}
	rf_gregions.normalize();

	return true;
}

double MCMC_SW_Cuts_2Way::ProposeAGRegion(int &indexid_gregion_selected)
{
	if (!PrepareToProposeGRegion(rf_gregions))
	{
		indexid_gregion_selected = -1;
		return 0.0;
	}
	else
	{
		indexid_gregion_selected = rf_gregions.SamplingIntNonSetCdf();

		sprintf(Info[0], "%d", indexid_gregion_selected);

		return rf_gregions.pdf(indexid_gregion_selected);
	}
}

double MCMC_SW_Cuts_2Way::Q_ProposeGRegion(int indexid_gregion_selected)
{
	if (!PrepareToProposeGRegion(rf_gregions))
		return 0.0;
	else
		return rf_gregions.pdf(indexid_gregion_selected);
}

double MCMC_SW_Cuts_2Way::EnergyOldAndSave(void)
{
	double energy;

	MCMC_GRegion *pgregion_tochange,*pgregion_nb;

	pgregion_tochange = (MCMC_GRegion*)player_region->GetRegionFromIndexId(indexid_tochange);
	assert(pgregion_tochange != NULL);
	// energy for the region is to change
	energy = pgregion_tochange->EnergyTotal();
	// remember the contents of this gregion
	gregion_buf1 = *pgregion_tochange;
	
	pgregion_nb = (MCMC_GRegion*)player_region->GetRegionFromIndexId(indexid_nb);
	if (pgregion_nb != NULL)
	{
		energy += pgregion_nb->EnergyTotal();
		gregion_buf2 = *pgregion_nb;
	}

	return energy;
}

double MCMC_SW_Cuts_2Way::ProposeModels(const int cue_selected_comp)
{
	// propose models
	int				imodel1,imodel2;
	MCMC_GRegion	*pgregion_new1,*pgregion_new2;
	LinkList<int>	list_aregions_new1,list_aregions_new2;
	MCMC_Model		*pmodel;
	double			q=1.0;

	pgregion_new1 = (MCMC_GRegion*) player_region->GetRegionFromIndexId(indexid_new1);
	assert(pgregion_new1 != NULL);
	pgregion_new1->GetAllAtomicRegions(list_aregions_new1);
	
	// model for the proposed part and neighbor
	imodel1 = pmodel_supervisor->ToModelType(cue_selected_comp);
	pmodel = pmodel_supervisor->CreateAndComputeModel(imodel1, list_aregions_new1);
	q *= pmodel->GetPdf();
	pgregion_new1->SetStat(pmodel);
	// intensity model
	energy2 = pgregion_new1->EnergyImageModel();
	// shape
	energy2 += pgregion_new1->ComputeEnergyShapeForList(list_aregions_new1);
	if (pmodel != NULL)
		delete pmodel;

	// model for the left over
	pgregion_new2 = (MCMC_GRegion*) player_region->GetRegionFromIndexId(indexid_new2);
	if (pgregion_new2 != NULL)
	{
		pgregion_new2->GetAllAtomicRegions(list_aregions_new2);

		q *= pmodel_supervisor->ProposeModelType(imodel2, list_aregions_new2);
		pmodel = pmodel_supervisor->CreateAndComputeModel(imodel2, list_aregions_new2);
		q *= pmodel->GetPdf();
		
		pgregion_new2->SetStat(pmodel);
		
		energy2 += pgregion_new2->EnergyImageModel();
		energy2 += pgregion_new2->ComputeEnergyShapeForList(list_aregions_new2);

		if (pmodel != NULL)
			delete pmodel;
	}
	return q;
}

double MCMC_SW_Cuts_2Way::Q_ProposeModel(const int indexid1, const int indexid2)
{
	MCMC_RegionElement *pregion;
	double q=1.0;

	pregion = player_region->GetRegionFromIndexId(indexid1);
	if (pregion != NULL && pregion->Model()!=NULL)
		q *= pregion->Model()->GetPdf();

	pregion = player_region->GetRegionFromIndexId(indexid2);
	if (pregion != NULL && pregion->Model()!=NULL)
		q *= pregion->Model()->GetPdf();

	return q;
}

void MCMC_SW_Cuts_2Way::ClearShowProposal(void)
{
	list_comp.Empty();
	list_rest.Empty();
	list_nb.Empty();
}


void MCMC_SW_Cuts_2Way::OneStep(void)
{
	// propose a gregion
	int				cue_selected_new;
	LinkList<int>	list_aregions_proposed,list_aregions_nb,list_aregions_left;
	MCMC_RegionElement *pgregion_tochange;

	Q1_2 = 1.0;
	Q2_1 = 1.0;

	// propose a gregion to change
	Q1_2 *= ProposeAGRegion(indexid_tochange);
	if (Q1_2 <= 0.0)
		return;
	
 	pgregion_tochange = player_region->GetRegionFromIndexId(indexid_tochange);
	assert(pgregion_tochange->Model() != NULL);
	sw_cut.cue_current = pmodel_supervisor->ToCueType(pgregion_tochange->Model()->Type());

	//SW-Cuts propose
	
	// what cues to use
	Q1_2 *= sw_cut.ProposeTwoCueTypes(indexid_tochange);

	Q1_2 *= sw_cut.Propose(indexid_tochange, list_gregions_ccp, cue_selected_new, indexid_nb, list_gregions_left);
	
	// propose models
	Q2_1 *= Q_ProposeModel(indexid_tochange, indexid_nb);

	energy1 = EnergyOldAndSave();
	
	// for display
	list_comp = list_gregions_ccp;
	list_rest = list_gregions_left;
	MCMC_RegionElement *pa;
	pa = player_region->GetRegionFromIndexId(indexid_nb);
	if (pa != NULL)
		pa->GetAllAtomicRegions(list_nb);
	else
		list_nb.Empty();

	//-----------
	// to compute the probablity for coming back
	
	// group and ungroup
	UngroupAndGroup(indexid_new1, indexid_new2, list_gregions_ccp, list_gregions_left, indexid_nb);
	
	sw_cut.ExchangeCueValues();
	// what cues to use
	Q2_1 *= sw_cut.QProposeTwoCueTypes(indexid_new1);

	// to propose the component
	Q2_1 *= sw_cut.Q_ProposeBack(indexid_new1, indexid_new2);

	// propose models
	Q1_2 *= ProposeModels(cue_selected_new);

	// accept or not
	TryAccept();
	
	//
	DoAction();

	sw_cut.ClearRecord();
}
